﻿namespace com.stifel.ProjectMgmtDao
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using com.stifel.Extensions.SharePointExtensions;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Linq;

    public class StifelProjectDao
    {
        #region Methods

        public List<StifelProject> GetActiveProjects( List<ProjectSite> sites )
        {
            List<StifelProject> list = new List<StifelProject>( );
            foreach ( ProjectSite site in sites )
            {
                List<StifelProject> l = getActiveProjects( site );
                list.AddRange( l );
            }
            // sort by overall ranking
            list.Sort( ( a, b ) => a.OverallRanking.Value.CompareTo( b.OverallRanking.Value ) );
            return list;
        }

        public string GetCurrentProjectsAsTsv( List<ProjectSite> sites )
        {
            bool x1 = false;
            StringBuilder sb = new StringBuilder( );
            List<StifelProject> projects = new List<StifelProject>( );
            projects.AddRange( GetActiveProjects( sites ) );
            projects.AddRange( GetNewProjects( sites ) );
            projects.AddRange( GetInactiveProjects( sites ) );
            foreach ( StifelProject project in projects )
            {
                if ( !x1 )
                {
                    sb.AppendLine( project.GetAsTsvTitles( ) );
                    x1 = true;
                }
                sb.AppendLine( project.GetAsTsv( ) );
            }
            string s = sb.ToString( );
            sb = null;
            return s;
        }

        public List<StifelProject> GetInactiveProjects( List<ProjectSite> sites )
        {
            List<StifelProject> list = new List<StifelProject>( );
            foreach ( ProjectSite site in sites )
            {
                List<StifelProject> l = getInactiveProjects( site );
                list.AddRange( l );
            }
            // sort by overall ranking
            list.Sort( ( a, b ) => a.OverallRanking.Value.CompareTo( b.OverallRanking.Value ) );
            return list;
        }

        public List<StifelProject> GetNewProjects( List<ProjectSite> sites )
        {
            List<StifelProject> list = new List<StifelProject>( );
            foreach ( ProjectSite site in sites )
            {
                List<StifelProject> l = getNewProjects( site );
                list.AddRange( l );
            }
            return list;
        }

        /// <summary>
        /// Get sites with projects defined. This is convention over config. The projects list must have the URL defined as /lists/projects. The title of the list, the site title, and the site url are returned. For example: The list url is /lists/projects, the title of the list is Xen Team Projects. Note: When creating the list, initially name the list projects so that the url is set correctly. The title of the list can be changed after the list creation.
        /// </summary>
        /// <param name="sitecollectionurl"></param>
        /// <returns></returns>
        public List<ProjectSite> GetSitesWithProjectsDefined( string sitecollectionurl )
        {
            const string PROJECTS = "projects";
            List<ProjectSite> sitesWithProjects = new List<ProjectSite>( );
            using ( SPSite spSite = new SPSite( sitecollectionurl ) )
            {
                using ( SPWeb spWeb = spSite.OpenWeb( ) )
                {
                    sitesWithProjects = spWeb.GetSubwebsForCurrentUser( ).Where( w => w.Lists.ContainsList( PROJECTS ) ).Select( w =>
                        {
                            SPList spList = w.Lists.GetListByRootFolder( PROJECTS );
                            return new ProjectSite
                            {
                                ListID = spList == null ? Guid.Empty : spList.ID,
                                ListTitle = spList == null ? string.Empty : spList.Title,
                                SiteTitle = w.Title,
                                SiteUrl = w.Url
                            };
                        } ).ToList( );
                }
            }
            return sitesWithProjects;
        }

        public void UpdateProjectsRanking( List<ProjectId> activeProjects, List<ProjectId> inactiveProjects )
        {
            updateActiveProjectsRanking( activeProjects );
            updateInactiveProjectsRanking( inactiveProjects, activeProjects.Count );
        }

        /// <summary>
        /// Active projects have project status of InProgress or NotStarted
        /// </summary>
        /// <param name="site"></param>
        /// <returns></returns>
        List<StifelProject> getActiveProjects( ProjectSite site )
        {
            List<StifelProject> list = new List<StifelProject>( );
            using ( StifelprojectDataContext c = new StifelprojectDataContext( site.SiteUrl ) )
            {
                EntityList<StifelProject> projects = c.GetList<StifelProject>( site.ListTitle );
                list = ( from project in projects
                         where
                             ( project.ProjectStatus == ProjectStatus.InProgress ||
                             project.ProjectStatus == ProjectStatus.NotStarted ) &&
                             project.OverallRanking > 0
                         select project ).ToList( );
            }
            list.ForEach( delegate( StifelProject a )
            {
                a.ParentSite = site;
                if ( !a.OverallRanking.HasValue )
                {
                    a.OverallRanking = 0;
                }
                if ( a.StartDate.HasValue && a.StartDate.Value > a.DueDate.Value )
                {
                    a.StartDate = a.DueDate;
                }
            } );
            return list;
        }

        /// <summary>
        /// Active projects have project status of InProgress or NotStarted
        /// </summary>
        /// <param name="site"></param>
        /// <returns></returns>
        List<StifelProject> getActiveProjects( ProjectSite site, System.Web.UI.Page p )
        {
            List<StifelProject> list = new List<StifelProject>( );
            using ( StifelprojectDataContext c = new StifelprojectDataContext( site.SiteUrl ) )
            {
                if ( p != null )
                    p.Response.Write( "<br/>full url of data context=" + c.Web );
                EntityList<StifelProject> projects = c.GetList<StifelProject>( site.ListTitle );
                list = ( from project in projects
                         where
                             project.ProjectStatus == ProjectStatus.InProgress ||
                             project.ProjectStatus == ProjectStatus.NotStarted
                         select project ).ToList( );
                ///
                if ( list.Count <= 0 ) if ( p != null )

                        p.Response.Write( "<br/>list has no items Projects has count=" + projects.Count( ) );
                ///
            }
            list.ForEach( delegate( StifelProject a )
            {
                a.ParentSite = site;
                if ( !a.OverallRanking.HasValue )
                {
                    a.OverallRanking = 0;
                }
            } );
            return list;
        }

        /// <summary>
        /// Inactive projects have project status that is not InProgress, NotStarted, and Completed
        /// </summary>
        /// <param name="site"></param>
        /// <returns></returns>
        List<StifelProject> getInactiveProjects( ProjectSite site )
        {
            List<StifelProject> list = new List<StifelProject>( );
            using ( StifelprojectDataContext c = new StifelprojectDataContext( site.SiteUrl ) )
            {
                EntityList<StifelProject> projects = c.GetList<StifelProject>( site.ListTitle );
                list = ( from project in projects
                         where
                             project.ProjectStatus != ProjectStatus.InProgress &&
                             project.ProjectStatus != ProjectStatus.NotStarted &&
                             project.ProjectStatus != ProjectStatus.Completed
                         select project ).ToList( );
            }
            list.ForEach( delegate( StifelProject a )
            {
                a.ParentSite = site;
                if ( !a.OverallRanking.HasValue )
                {
                    a.OverallRanking = Double.MaxValue;
                }
            } );
            return list;
        }

        /// <summary>
        /// This sets the starting point 100+ over the number of active projects
        /// </summary>
        /// <param name="numberOfActiveProjects"></param>
        /// <returns></returns>
        int getInactiveProjectsStartRanking( int numberOfActiveProjects )
        {
            int i = numberOfActiveProjects;
            int j = 100 - ( i + 100 ) % 100;
            j = j < 75 ? j + 100 : j;
            int k = i + 100 + j + 1;
            return k;
        }

        /// <summary>
        /// New projects have project status of InProgress or NotStarted and an OverallRanking of zero
        /// </summary>
        /// <param name="site"></param>
        /// <returns></returns>
        List<StifelProject> getNewProjects( ProjectSite site )
        {
            List<StifelProject> list = new List<StifelProject>( );
            using ( StifelprojectDataContext c = new StifelprojectDataContext( site.SiteUrl ) )
            {
                EntityList<StifelProject> projects = c.GetList<StifelProject>( site.ListTitle );
                list = ( from project in projects
                         where
                             ( project.ProjectStatus == ProjectStatus.InProgress ||
                             project.ProjectStatus == ProjectStatus.NotStarted ) &&
                             ( !project.OverallRanking.HasValue ||
                             project.OverallRanking == 0 )
                         select project ).ToList( );
            }
            list.ForEach( delegate( StifelProject a )
            {
                a.ParentSite = site;
                if ( !a.OverallRanking.HasValue )
                {
                    a.OverallRanking = 0;
                }
            } );
            return list;
        }

        void updateActiveProjectsRanking( List<ProjectId> values )
        {
            // set the order
            int i = 1;
            values.ForEach( delegate( ProjectId a )
            {
                a.Order = i;
                i++;
            } );
            // get distinct list of site Urls
            List<string> siteUrls = values.Select( a => a.SiteUrl ).Distinct( ).ToList( );
            // for each of the site Urls
            siteUrls.ForEach( delegate( string siteUrl )
            {
                int j = 1; // team ranking
                using ( StifelprojectDataContext c = new StifelprojectDataContext( siteUrl ) )
                {
                    List<ProjectId> projects = ( from p in values
                                                 where p.SiteUrl.Equals( siteUrl, StringComparison.OrdinalIgnoreCase )
                                                 select p ).ToList( );
                    projects.Sort( ( a, b ) => a.Order.CompareTo( b.Order ) );
                    // get the site projects list
                    EntityList<StifelProject> teamProjects = c.GetList<StifelProject>( projects[ 0 ].ListTitle );
                    // for each of the ordered projects for this site
                    projects.ForEach( delegate( ProjectId a )
                    {
                        // get the current project item from the list
                        StifelProject teamProject = ( from p in teamProjects
                                                      where p.UniqueId.Equals( a.ItemId )
                                                      select p ).SingleOrDefault( );
                        // update overall ranking and determine team ranking
                        if ( teamProject != null )
                        {
                            teamProject.OverallRanking = a.Order;
                            teamProject.TeamRanking = j;
                            j++;

                            // ensure valid project status
                            if ( !teamProject.ProjectStatus.HasValue )
                                teamProject.ProjectStatus = ProjectStatus.InProgress;
                            else if ( teamProject.ProjectStatus.Value != ProjectStatus.InProgress )
                                teamProject.ProjectStatus = ProjectStatus.InProgress;
                        }
                    } );
                    // commit changes to projects list
                    c.SubmitChanges( );
                }
            } );
        }

        void updateInactiveProjectsRanking( List<ProjectId> values, int numberOfActiveProjects )
        {
            // set the order
            int k = getInactiveProjectsStartRanking( numberOfActiveProjects );
            int i = k;
            values.ForEach( delegate( ProjectId a )
            {
                a.Order = i;
                i++;
            } );
            // get distinct list of site Urls
            List<string> siteUrls = values.Select( a => a.SiteUrl ).Distinct( ).ToList( );
            // for each of the site Urls
            siteUrls.ForEach( delegate( string siteUrl )
            {
                int j = k; // team ranking
                using ( StifelprojectDataContext c = new StifelprojectDataContext( siteUrl ) )
                {
                    List<ProjectId> projects = ( from p in values
                                                 where p.SiteUrl.Equals( siteUrl, StringComparison.OrdinalIgnoreCase )
                                                 select p ).ToList( );
                    projects.Sort( ( a, b ) => a.Order.CompareTo( b.Order ) );
                    // get the site projects list
                    EntityList<StifelProject> teamProjects = c.GetList<StifelProject>( projects[ 0 ].ListTitle );
                    // for each of the ordered projects for this site
                    projects.ForEach( delegate( ProjectId a )
                    {
                        // get the current project item from the list
                        StifelProject teamProject = ( from p in teamProjects
                                                      where p.UniqueId.Equals( a.ItemId )
                                                      select p ).SingleOrDefault( );
                        // update overall ranking and determine team ranking
                        if ( teamProject != null )
                        {
                            teamProject.OverallRanking = a.Order;
                            teamProject.TeamRanking = j;
                            j++;

                            // ensure valid project status
                            if ( !teamProject.ProjectStatus.HasValue )
                                teamProject.ProjectStatus = ProjectStatus.Deferred;
                            else if ( teamProject.ProjectStatus.Value != ProjectStatus.Deferred )
                                teamProject.ProjectStatus = ProjectStatus.Deferred;
                        }
                    } );
                    // commit changes to projects list
                    c.SubmitChanges( );
                }
            } );
        }

        #endregion Methods
    }
}